package com.wang.gallerybackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.gallerybackend.api.aliyunai.AliYunAiApi;
import com.wang.gallerybackend.api.aliyunai.model.CreateOutPaintingTaskRequest;
import com.wang.gallerybackend.api.aliyunai.model.CreateOutPaintingTaskResponse;
import com.wang.gallerybackend.constant.UserConstant;
import com.wang.gallerybackend.exception.BusinessException;
import com.wang.gallerybackend.exception.ErrorCode;
import com.wang.gallerybackend.exception.ThrowUtils;
import com.wang.gallerybackend.manager.CosManager;
import com.wang.gallerybackend.manager.upload.FilePictureUploadImpl;
import com.wang.gallerybackend.manager.upload.PictureUpload;
import com.wang.gallerybackend.manager.upload.UrlPictureUploadImpl;
import com.wang.gallerybackend.model.dto.file.UploadPictureResult;
import com.wang.gallerybackend.model.dto.picture.*;
import com.wang.gallerybackend.model.entity.Picture;
import com.wang.gallerybackend.model.entity.Space;
import com.wang.gallerybackend.model.entity.User;
import com.wang.gallerybackend.model.enums.PictureReviewStatusEnum;
import com.wang.gallerybackend.model.vo.PictureVO;
import com.wang.gallerybackend.model.vo.UserVO;
import com.wang.gallerybackend.service.PictureService;
import com.wang.gallerybackend.mapper.PictureMapper;
import com.wang.gallerybackend.service.SpaceService;
import com.wang.gallerybackend.service.UserService;
import com.wang.gallerybackend.utils.ColorSimilarUtils;
import com.wang.gallerybackend.utils.ColorTransformUtils;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 汪
 * @description 针对表【picture(图片信息表)】的数据库操作Service实现
 */
@Service
@Slf4j
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
		implements PictureService {
	@Resource
	private UserService userService;
	@Resource
	private FilePictureUploadImpl filePictureUpload;
	@Resource
	private UrlPictureUploadImpl urlPictureUpload;
	@Autowired
	private CosManager cosManager;
	@Resource
	private SpaceService spaceService;
	@Resource
	private TransactionTemplate transactionTemplate;
	@Resource
	private AliYunAiApi aliYunAiApi;

	@Override
	public void validPicture(Picture picture) {
		ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
		// 从对象中取值
		Long id = picture.getId();
		String url = picture.getUrl();
		String introduction = picture.getIntroduction();
		// 修改数据时，id 不能为空，有参数则校验
		ThrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空");
		// 如果传递了 url，才校验
		if (StrUtil.isNotBlank(url)) {
			ThrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长");
		}
		if (StrUtil.isNotBlank(introduction)) {
			ThrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长");
		}
	}

	@Override
	public PictureVO uploadPicture(Object inputSource, PictureUploadDTO pictureUploadDTO, User loginUser) {
		//校验参数
		if (loginUser == null) {
			throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
		}
		//校验空间是否存在
		Long spaceId = pictureUploadDTO.getSpaceId();
		if (spaceId != null) {
			Space space = spaceService.getById(spaceId);
			ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
		/*	//校验是否有空间的权限
			if (!space.getUserId().equals(loginUser.getId())) {
				throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
			}*/
			//校验额度
			if (space.getTotalCount() >= space.getMaxCount()) {
				throw new BusinessException(ErrorCode.OPERATION_ERROR, "空间条数不足");
			}
			if (space.getTotalSize() >= space.getMaxSize()) {
				throw new BusinessException(ErrorCode.OPERATION_ERROR, "空间大小不足");
			}
		}
		//判断是新增还是删除
		Long pictureId = null;
		if (pictureUploadDTO != null) {
			pictureId = pictureUploadDTO.getId();
		}
		//如果是更新，则要判断图片是否存在
		if (pictureId != null) {
			Picture oldPicture = this.getById(pictureId);
			ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
			//仅本人或管理员可修改
			/*if (!loginUser.getId().equals(oldPicture.getUserId()) && !userService.isAdmin(loginUser)) {
				throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
			}*/
			//校验空间是否一致
			//没传spaceId，则使用原有的id
			if (spaceId == null) {
				if (oldPicture.getSpaceId() != null) {
					spaceId = oldPicture.getSpaceId();
				}
			} else {
				//必须和之前图片的空间一致
				if (ObjUtil.notEqual(spaceId, oldPicture.getSpaceId())) {
					throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间不一致");
				}
			}
		}
		//上传图片
		//按照用户id创建图片上传路径,按照空间划分目录
		String uploadPathPrefix;
		if (spaceId == null) {
			//公共图片
			uploadPathPrefix = String.format("public/%s", loginUser.getId());
		} else {
			//私有图片
			uploadPathPrefix = String.format("space/%s", spaceId);
		}

		//根据inputSource类型区分上传方式
		PictureUpload pictureUpload = filePictureUpload;
		if (inputSource instanceof String) {
			pictureUpload = urlPictureUpload;
		}
		UploadPictureResult uploadPictureResult = pictureUpload.uploadPicture(inputSource, uploadPathPrefix);
		//构造要入库的图片信息
		Picture picture = new Picture();
		BeanUtil.copyProperties(uploadPictureResult, picture);
		picture.setPicColor(ColorTransformUtils.getStandardColor(uploadPictureResult.getPicColor()));
		picture.setSpaceId(spaceId);
		if (pictureUploadDTO.getPicName() != null && StrUtil.isNotBlank(pictureUploadDTO.getPicName())) {
			picture.setName(pictureUploadDTO.getPicName());
		}
		picture.setUserId(loginUser.getId());
		//补充审核参数
		this.fillReviewParams(picture, loginUser);
		//添加图片信息
		//如果pictureId不为空，则更新图片信息
		if (pictureId != null) {
			//更新图片信息
			picture.setId(pictureId);
			picture.setEditTime(new Date());
		}
		//更新空间的使用额度
		Long finalSpaceId = spaceId;
		transactionTemplate.execute(status -> {
			//如果pictureId为空，则添加图片信息
			boolean result = this.saveOrUpdate(picture);

			if (!result) {
				throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存图片信息失败");
			}
			if (finalSpaceId != null) {
				boolean update = spaceService.lambdaUpdate().eq(Space::getId, finalSpaceId)
						.setSql("totalSize=totalSize+" + picture.getPicSize())
						.setSql("totalCount=totalCount+1").update();
				ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR, "额度更新失败");
			}
			return picture;
		});
		return PictureVO.toVO(picture);
	}

	@Override
	public QueryWrapper<Picture> getQueryWrapper(PictureQueryRequest pictureQueryRequest) {
		QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
		if (pictureQueryRequest == null) {
			return queryWrapper;
		}
		// 从对象中取值
		Long id = pictureQueryRequest.getId();
		String name = pictureQueryRequest.getName();
		String introduction = pictureQueryRequest.getIntroduction();
		String category = pictureQueryRequest.getCategory();
		List<String> tags = pictureQueryRequest.getTags();
		Long picSize = pictureQueryRequest.getPicSize();
		Integer picWidth = pictureQueryRequest.getPicWidth();
		Integer picHeight = pictureQueryRequest.getPicHeight();
		Double picScale = pictureQueryRequest.getPicScale();
		String picFormat = pictureQueryRequest.getPicFormat();
		String searchText = pictureQueryRequest.getSearchText();
		Long userId = pictureQueryRequest.getUserId();
		Integer reviewStatus = pictureQueryRequest.getReviewStatus();
		String reviewMessage = pictureQueryRequest.getReviewMessage();
		Long reviewerId = pictureQueryRequest.getReviewerId();
		Long spaceId = pictureQueryRequest.getSpaceId();
		Date startEditTime = pictureQueryRequest.getStartEditTime();
		Date endEditTime = pictureQueryRequest.getEndEditTime();
		boolean nullSpaceId = pictureQueryRequest.isNullSpaceId();
		String sortField = pictureQueryRequest.getSortField();
		String sortOrder = pictureQueryRequest.getSortOrder();
		// 从多字段中搜索
		if (StrUtil.isNotBlank(searchText)) {
			// 需要拼接查询条件
			// and (name like "%xxx%" or introduction like "%xxx%")
			queryWrapper.and(
					qw -> qw.like("name", searchText)
							.or()
							.like("introduction", searchText)
			);
		}
		queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
		queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
		queryWrapper.eq(ObjUtil.isNotEmpty(spaceId), "spaceId", spaceId);
		queryWrapper.isNull(nullSpaceId, "spaceId");
		queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
		queryWrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
		queryWrapper.like(StrUtil.isNotBlank(picFormat), "picFormat", picFormat);
		queryWrapper.like(StrUtil.isNotBlank(reviewMessage), "reviewMessage", reviewMessage);
		queryWrapper.eq(StrUtil.isNotBlank(category), "category", category);
		queryWrapper.eq(ObjUtil.isNotEmpty(picWidth), "picWidth", picWidth);
		queryWrapper.eq(ObjUtil.isNotEmpty(picHeight), "picHeight", picHeight);
		queryWrapper.eq(ObjUtil.isNotEmpty(picSize), "picSize", picSize);
		queryWrapper.eq(ObjUtil.isNotEmpty(picScale), "picScale", picScale);
		queryWrapper.eq(ObjUtil.isNotEmpty(reviewStatus), "reviewStatus", reviewStatus);
		queryWrapper.eq(ObjUtil.isNotEmpty(reviewerId), "reviewerId", reviewerId);
		// >= startEditTime
		queryWrapper.ge(ObjUtil.isNotEmpty(startEditTime), "editTime", startEditTime);
		// < endEditTime
		queryWrapper.lt(ObjUtil.isNotEmpty(endEditTime), "editTime", endEditTime);
		// JSON 数组查询
		if (CollUtil.isNotEmpty(tags)) {
			/* and (tag like "%\"Java\"%" and like "%\"Python\"%") */
			for (String tag : tags) {
				queryWrapper.like("tags", "\"" + tag + "\"");
			}
		}
		// 排序
		queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), "ascend".equals(sortOrder), sortField);
		return queryWrapper;
	}

	@Override
	public PictureVO getPictureVO(Picture picture, HttpServletRequest request) {
		// 对象转封装类
		PictureVO pictureVO = PictureVO.toVO(picture);
		// 关联查询用户信息
		Long userId = picture.getUserId();
		if (userId != null && userId > 0) {
			User user = userService.getById(userId);
			UserVO userVO = userService.getUserVO(user);
			pictureVO.setUser(userVO);
		}
		return pictureVO;
	}


	/**
	 * 分页获取图片封装
	 */
	@Override
	public Page<PictureVO> getPictureVOPage(Page<Picture> picturePage, HttpServletRequest request) {
		List<Picture> pictureList = picturePage.getRecords();
		Page<PictureVO> pictureVOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal());
		if (CollUtil.isEmpty(pictureList)) {
			return pictureVOPage;
		}
		// 对象列表 => 封装对象列表
		List<PictureVO> pictureVOList = pictureList.stream()
				.map(PictureVO::toVO)
				.collect(Collectors.toList());
		// 1. 关联查询用户信息
		// 1,2,3,4
		Set<Long> userIdSet = pictureList.stream().map(Picture::getUserId).collect(Collectors.toSet());
		// 1 => user1, 2 => user2
		Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
				.collect(Collectors.groupingBy(User::getId));
		// 2. 填充信息
		pictureVOList.forEach(pictureVO -> {
			Long userId = pictureVO.getUserId();
			User user = null;
			if (userIdUserListMap.containsKey(userId)) {
				user = userIdUserListMap.get(userId).get(0);
			}
			pictureVO.setUser(userService.getUserVO(user));
		});
		pictureVOPage.setRecords(pictureVOList);
		return pictureVOPage;
	}

	@Override
	public void editPicture(PictureEditRequest pictureEditRequest, User loginUser) {
		// 在此处将实体类和 DTO 进行转换
		Picture picture = new Picture();
		BeanUtils.copyProperties(pictureEditRequest, picture);
		// 注意将 list 转为 string
		picture.setTags(JSONUtil.toJsonStr(pictureEditRequest.getTags()));
		// 设置编辑时间
		picture.setEditTime(new Date());
		// 数据校验
		this.validPicture(picture);
		// 判断是否存在
		long id = pictureEditRequest.getId();
		Picture oldPicture = this.getById(id);
		ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
		//校验权限
		//改为使用注解鉴权
		/*	this.checkPictureAuth(oldPicture, loginUser);*/
		//补充审核参数
		this.fillReviewParams(picture, loginUser);
		// 操作数据库
		boolean result = this.updateById(picture);
		ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
	}

	@Override
	public void doPictureReview(PictureReviewRequest pictureReviewRequest, User loginUser) {
		//1. 参数校验
		ThrowUtils.throwIf(pictureReviewRequest == null, ErrorCode.PARAMS_ERROR);
		Long id = pictureReviewRequest.getId();
		Integer reviewStatus = pictureReviewRequest.getReviewStatus();
		PictureReviewStatusEnum reviewStatusEnum = PictureReviewStatusEnum.getEnumByValue(reviewStatus);
		String reviewMessage = pictureReviewRequest.getReviewMessage();
		ThrowUtils.throwIf(id <= 0 || reviewStatusEnum == null || reviewStatus < 0 || reviewStatus > 2
				|| PictureReviewStatusEnum.UNREVIEWED.equals(reviewStatusEnum), ErrorCode.PARAMS_ERROR);
		//2. 判断图片是否存在
		Picture oldPicture = this.getById(id);
		ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
		//3. 校验审核状态是否重复
		if (oldPicture.getReviewStatus().equals(reviewStatus)) {
			throw new BusinessException(ErrorCode.OPERATION_ERROR, "图片已审核通过");
		}
		//4. 更新图片审核信息
		Picture updatePicture = new Picture();
		BeanUtil.copyProperties(pictureReviewRequest, updatePicture);
		updatePicture.setReviewerId(loginUser.getId());
		updatePicture.setReviewTime(new Date());
		boolean result = this.updateById(updatePicture);
		ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
	}

	@Override
	public void fillReviewParams(Picture picture, User loginUser) {
		if (userService.isAdmin(loginUser)) {
			//管理员自动通过
			picture.setReviewStatus(PictureReviewStatusEnum.REVIEW_PASS.getValue());
			picture.setReviewerId(loginUser.getId());
			picture.setReviewTime(new Date());
			picture.setReviewMessage("管理员自动审核通过");
		} else {
			//普通用户审核中
			picture.setReviewStatus(PictureReviewStatusEnum.UNREVIEWED.getValue());
		}
	}

	@Override
	public Integer uploadPictureByBitch(PictureUploadByBatchRequest pictureUploadByBatchRequest, User loginUser) {
		//校验参数
		Integer count = pictureUploadByBatchRequest.getCount();
		String searchText = pictureUploadByBatchRequest.getSearchText();
		ThrowUtils.throwIf(count <= 0 || count > 30, ErrorCode.PARAMS_ERROR, "最多三十条数据");
		//抓取内容
		// 对中文关键词进行URL编码
		String encodedSearchText = "";
		if (StrUtil.isNotBlank(searchText)) {
			try {
				// 对中文等特殊字符进行URL编码（关键步骤）
				encodedSearchText = URLEncoder.encode(searchText, StandardCharsets.UTF_8.name());
			} catch (UnsupportedEncodingException e) {
				log.error("关键词编码失败", e);
				throw new BusinessException(ErrorCode.SYSTEM_ERROR, "关键词处理失败");
			}
		}
		// 拼接编码后的URL
		String fetchUrl = String.format("https://cn.bing.com/images/async?q=%s&mmasync=1", encodedSearchText);
		Document document;
		try {
			document = Jsoup.connect(fetchUrl)
					// 1. 模拟 Chrome 浏览器的 User-Agent（关键）
					.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36")
					// 2. 接受的内容类型
					.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
					// 3. 支持的语言
					.header("Accept-Language", "zh-CN,zh;q=0.9")
					// 4. 模拟从 Bing 首页跳转过来（防盗链检测）
					.header("Referer", "https://cn.bing.com/")
					// 5. 保持连接
					.header("Connection", "keep-alive")
					// 6. 延长超时时间（避免网络慢导致失败）
					.timeout(10000)
					// 执行请求
					.get();
		} catch (IOException e) {
			// 打印完整异常信息（包括状态码、错误原因）
			log.error("Jsoup 抓取失败，URL: {}，错误信息: {}", fetchUrl, e.getMessage(), e);
			throw new BusinessException(ErrorCode.SYSTEM_ERROR, "图片抓取失败：" + e.getMessage());
		}
		//解析内容
		Element div = document.getElementsByClass("dgControl").first();
		if (ObjUtil.isEmpty(div)) {
			throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取元素失败");
		}
		Elements imgElementsList = div.select("img.mimg");
		//遍历元素，依次上传图片
		int uploadCount = 0;
		//取到名字的前缀
		String picNamePrefix = pictureUploadByBatchRequest.getNamePrefix();
		//默认名字前缀为搜索内容
		if (StrUtil.isBlank(picNamePrefix)) {
			picNamePrefix = searchText;
		}
		for (Element imgElement : imgElementsList) {
			String fileUrl = imgElement.attr("src");
			if (StrUtil.isBlank(fileUrl)) {
				log.info("当前链接为空，已跳过:{}", fileUrl);
				continue;
			}
			//处理图片地址，防止转义3和对象存储冲突的问题
			int questionIndex = fileUrl.indexOf("?");
			if (questionIndex > -1) {
				fileUrl = fileUrl.substring(0, questionIndex);
			}

			PictureUploadDTO pictureUploadDTO = new PictureUploadDTO();
			//构造名称
			pictureUploadDTO.setPicName(picNamePrefix + (uploadCount + 1));
			pictureUploadDTO.setFileUrl(fileUrl);
			try {
				//上传图片
				PictureVO pictureVO = this.uploadPicture(fileUrl, pictureUploadDTO, loginUser);
				log.info("上传图片成功:{}", pictureVO.getId());
				uploadCount++;
			} catch (Exception e) {
				log.error("上传图片失败:{}", e.getMessage());
				continue;
			}
			if (uploadCount >= count) {
				break;
			}
		}
		return uploadCount;
	}

	@Async
	@Override
	public void clearPictureFile(Picture oldPicture) {
		//判断该图片是否被多条记录使用
		String url = oldPicture.getUrl();
		long count = this.lambdaQuery().eq(Picture::getUrl, url).
				count();
		//仅当该图片被一条记录使用时才删除
		if (count > 1) {
			return;
		}
		//删除图片
		cosManager.deleteObject(url);
		//删除缩略图
		String thumbnailUrl = oldPicture.getThumbnailUrl();
		if (StrUtil.isNotBlank(thumbnailUrl)) {
			cosManager.deleteObject(thumbnailUrl);
		}

	}

	@Deprecated
	@Override
	public void checkPictureAuth(Picture picture, User loginUser) {
		Long spaceId = picture.getSpaceId();
		Long userId = loginUser.getId();
		if (spaceId == null) {
			//公共图片，仅本人和管理员可修改
			if (!picture.getUserId().equals(userId) && !userService.isAdmin(loginUser)) {
				throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
			}
		} else {
			if (!picture.getUserId().equals(userId)) {
				throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
			}
		}
	}

	@Override
	public void deletePicture(long pictureId, User loginUser) {
		Picture oldPicture = this.getById(pictureId);
		if (oldPicture == null) {
			throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
		}
		// 校验权限
		//改为使用注解鉴权
		/*	this.checkPictureAuth(oldPicture, loginUser);*/

		//开启事务
		transactionTemplate.execute(status -> {
			boolean result = this.removeById(pictureId);
			if (!result) {
				throw new BusinessException(ErrorCode.OPERATION_ERROR);
			}
			//释放额度
			boolean update = spaceService.lambdaUpdate().eq(Space::getId, oldPicture.getSpaceId())
					.setSql("totalSize=totalSize+" + oldPicture.getPicSize())
					.setSql("totalCount=totalCount-1").update();
			ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR, "额度更新失败");
			return oldPicture;
		});
		// 清除图片文件
		this.clearPictureFile(oldPicture);
	}

	@Override
	public List<PictureVO> searchPictureByColor(Long spaceId, String picColor, User loginUser) {
		//1. 校验参数
		ThrowUtils.throwIf(spaceId == null || StrUtil.isBlank(picColor), ErrorCode.PARAMS_ERROR);
		ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_AUTH_ERROR);
		Space space = spaceService.getById(spaceId);
		ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
		//2.校验权限
		if (!loginUser.getId().equals(space.getUserId())) {
			throw new BusinessException(ErrorCode.NOT_AUTH_ERROR, "没有空间访问权限");
		}
		//3.查询空间下的所有图片
		List<Picture> pictureList = this.lambdaQuery()
				.eq(Picture::getSpaceId, spaceId)
				.isNotNull(Picture::getPicColor)
				.list();
		//如果没有图片，返回空列表
		if (pictureList.isEmpty()) {
			return new ArrayList<>();
		}
		//4. 将字符串转化成主色调
		Color picColorColor = Color.decode(picColor);
		//5.计算相似度排序
		List<Picture> sortPictureList = pictureList
				.stream()
				.sorted(Comparator.comparingDouble(picture -> {
					//计算相似度
					String hexColor = picture.getPicColor();
					if (StrUtil.isBlank(hexColor)) {
						return Double.MAX_VALUE;
					}
					Color color = Color.decode(hexColor);
					return -ColorSimilarUtils.calculateSimilarity(picColorColor, color);
				})).limit(12)
				.collect(Collectors.toList());

		//6.转换结果
		List<PictureVO> pictureVoList = sortPictureList
				.stream()
				.map(PictureVO::toVO)
				.collect(Collectors.toList());
		return pictureVoList;
	}

	@Override
	public void editPictureByBatch(PictureEditByBatchRequest pictureEditByBatchRequest, User loginUser) {
		// 1. 获取和校验参数
		List<Long> pictureIdList = pictureEditByBatchRequest.getPictureIdList();
		Long spaceId = pictureEditByBatchRequest.getSpaceId();
		String category = pictureEditByBatchRequest.getCategory();
		List<String> tags = pictureEditByBatchRequest.getTags();
		ThrowUtils.throwIf(CollUtil.isEmpty(pictureIdList), ErrorCode.PARAMS_ERROR);
		ThrowUtils.throwIf(spaceId == null, ErrorCode.PARAMS_ERROR);
		ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_AUTH_ERROR);
		// 2. 校验空间权限
		Space space = spaceService.getById(spaceId);
		ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
		if (!space.getUserId().equals(loginUser.getId())) {
			throw new BusinessException(ErrorCode.NOT_AUTH_ERROR, "没有空间访问权限");
		}
		// 3. 查询指定图片（仅选择需要的字段）
		List<Picture> pictureList = this.lambdaQuery()
				.select(Picture::getId, Picture::getSpaceId)
				.eq(Picture::getSpaceId, spaceId)
				.in(Picture::getId, pictureIdList)
				.list();
		if (pictureList.isEmpty()) {
			return;
		}
		// 4. 更新分类和标签
		pictureList.forEach(picture -> {
			if (StrUtil.isNotBlank(category)) {
				picture.setCategory(category);
			}
			if (CollUtil.isNotEmpty(tags)) {
				picture.setTags(JSONUtil.toJsonStr(tags));
			}
		});
		// 批量重命名
		String nameRule = pictureEditByBatchRequest.getNameRule();
		fillPictureWithNameRule(pictureList, nameRule);
		// 5. 操作数据库进行批量更新
		boolean result = this.updateBatchById(pictureList);
		ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "批量编辑失败");
	}

	@Override
	public CreateOutPaintingTaskResponse createPictureOutPaintingTask(CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest, User loginUser) {
		Long pictureId = createPictureOutPaintingTaskRequest.getPictureId();

		Picture picture = Optional.ofNullable(this.getById(pictureId)).orElseThrow(
				() -> new BusinessException(ErrorCode.NOT_FOUND_ERROR));
		//改为使用注解鉴权-
		/*	checkPictureAuth(picture,loginUser);*/
		//构造请求参数
		CreateOutPaintingTaskRequest createOutPaintingTaskRequest = new CreateOutPaintingTaskRequest();
		CreateOutPaintingTaskRequest.Input input = new CreateOutPaintingTaskRequest.Input();
		input.setImageUrl(picture.getUrl());
		createOutPaintingTaskRequest.setInput(input);
		createOutPaintingTaskRequest.setParameters(createPictureOutPaintingTaskRequest.getParameters());
		//创建任务
		return aliYunAiApi.createOutPaintingTask(createOutPaintingTaskRequest);
	}

	/**
	 * nameRule 格式：图片{序号}
	 *
	 * @param pictureList
	 * @param nameRule
	 */
	private void fillPictureWithNameRule(List<Picture> pictureList, String nameRule) {
		if (StrUtil.isBlank(nameRule) || CollUtil.isEmpty(pictureList)) {
			return;
		}
		long count = 1;
		try {
			for (Picture picture : pictureList) {
				String pictureName = nameRule.replaceAll("\\{序号}", String.valueOf(count++));
				picture.setName(pictureName);
			}
		} catch (Exception e) {
			log.error("名称解析错误", e);
			throw new BusinessException(ErrorCode.OPERATION_ERROR, "名称解析错误");
		}
	}

}